查看原文
其他

容器云实践分享之容器调度管理

汪照辉 王作敬 twt企业IT社区 2024-02-18

容器云平台构建运行了也有一段时间了,整体来说还算平稳,业务服务运营正常。年前内部团队计划测试机器学习平台,打算基于容器云部署机器学习平台,同时和大数据平台集成。根据我们最初的规划,也希望把机器学习服务和大数据服务等部署于容器云平台,逐步构建企业级的服务中台;同时我们也希望能验证一下容器云平台的能力,继续的完善。所以我们和机器学习团队一起进行了机器学习PoC测试,中间遇到了一些问题,也让我们扩展了不少思路。摸索着实践,实践中前进,前进中完善。

一、 问题提出

(一) 直接调用Kubernetes API和Docker API问题

机器学习平台PoC测试启动后,有家厂商要求直接访问Kubernetes API,允许其应用访问Kubernetes的API Server来控制容器的拉起、关闭、扩展、资源配置等。我们容器平台设计是没有考虑开放Kubernetes API访问权限的。为了平台的安全和管理的便利,我们希望所有的操作都可以在管理界面上来实现,容器的弹性伸缩可以通过策略配置满足需求。但明显还是无法满足机器学习根据需要拉起不同的模型容器的要求。机器学习应用平台可能需要调用不同的模型进行运算学习,不同的模型可能需要拉起不同的容器,这样就无法在界面上控制,只能通过编码在Kubernetes层来实现。

经过考虑我们觉得这是一个合理的需求,容器平台开放Kubernetes API,支持业务应用调用Kubernetes API接口实现容器的自动启停扩展调度,是最简单的方式,但安全方面需要做好。另外有个问题是,这样的话业务就和Kubernetes调度管理层紧耦合了,和我们设计的初衷又相背离。比如如果我们将来需要从Kubernetes切换到Openshift,那么应用就需要修改,这是我们不希望看到的。而且平台安全性就无从保证,对于弱安全的容器平台来说,你无法保证由于开发人员的失误调度导致整个平台崩溃的情况不会出现。

那就只能在平台层做抽象封装了,把需要的功能一一映射封装,实现容器通过平台API自定义调度、启停、扩缩容等能力,安全控制在平台层API实现。在一时无法实现API封装的情况下,我们在测试环境开放Kubernetes API用于PoC测试。

(二) 租户资源调度问题

为测试厂商配置了租户账户并分配资源之后,由厂商使用租户账号登录并部署应用。厂商上传镜像后使用yaml文件部署服务,但却发现部署的容器没有调度到该租户所分配的资源节点上,所以导致服务无法运行。后分析发现厂商的yaml文件中没有考虑租户隔离,在资源调度时没有根据租户的资源进行过滤,调度到了别的空闲节点上了。

采用租户隔离机制一方面也是为了安全,也避免彼此干扰。租户只能管理分配自己拥有的资源,租户应用只能部署于自有的资源之上,现在调度到了别的租户的资源节点上了,这可不是我们希望看到的事情。不过从另外方面看也暴露了容器平台租户资源隔离的问题,也让我们有了更深的认识,能有针对性的解决存在的安全隐患。

作为测试的临时解决方案,我们在yaml文件中增加nodeSelector选项,nodeSelector是Pod部署时一种简单的资源过滤选项。可以通过标签来指定资源范围。标签有内建标签和用户自定义标签,我们会在下篇标签设计中详细讨论容器云平台的标签设计和应用。内建标签kubernetes.io/hostname可以指定具体的node节点,有时也称做强绑定,通过自定义标签选择一个资源调度范围,称为弱绑定。容器资源调度可以是亲和性的或者反亲和性的,通常需要根据实际的情况来选择。比如容器部署于虚拟机上,如果几个虚拟机的宿主机都是同一台物理服务器,在物理服务器出现异常时,往往达不到容错的目的,所以同一个物理宿主机的虚拟机在容器部署时可能采用反亲和策略,通过这些虚拟机上的物理宿主机相同的标签就可以在nodeSelector选项中实现。

租户的资源节点可能会变化,所以实际的生产环境中可能不适合使用强绑定的方式,而且这样也失去了云计算的特点和优势。同时我们希望租户资源节点变化时,我们不用再去修改yaml文件,这些工作最好由平台来完成,跟用户应用没有关系,对用户透明。

(三) Namespace问题

在测试中有厂商要求为某个应用创建多个namespace,但在我们容器平台并没有namespace的概念。资源是分配给每个租户的,租户管理自己的计算、存储、网络等资源。我们知道从Kubernetes技术框架来说,默认虽然大多数kubernetes资源(例如pods、service、replication controllers等)都位于某些命名空间中。但是Nodes和PersistentVolumes等低级资源不在任何命名空间中,这也是上面我们提到节点调度遇到的问题。通过namespace来隔离一个应用不同服务的资源,使用场景似乎不是很合适。

Kubernetes支持一个物理集群内多个虚拟集群,这些虚拟集群被称为namespace。Namespace用于多用户分布于多个团队或项目中时的环境中。通常几个用户或几十个用户可能不需要namespace,真正需要namespace特性的时候(比如一个用户跨多个租户/项目)才需要考虑使用它。一个namespace内资源的名称是唯一的,它是多个租户之间划分集群资源的一种方式。Kubernetes将来的版本中,同一个namespace中的对象具有相同的访问控制策略。因此我们觉得namespace是适合定义租户资源范围的一个对象(Kubernetes namespace示例是隔离开发、生产多环境场景)。

每个namespace都可以定义资源配额(Resource Quote),其跟踪namespace中资源的聚合使用情况,包括计算资源、存储资源和对象数。Pod的资源配额和Namespace的资源配额是两回事,可能对Kubernetes文档示例的错误理解使有些人错误的认为一个Pod需要定义一个Namespace。Pod只是在Namespace中,使用namespace的部分资源而已。

二、 问题扩展思考

最初我们考虑安全、松耦合等因素,所有操作要求通过界面功能来实现,禁用容器终端,也未开放Kubernets API能力。但对于一些场景需要访问Kubernets API或者Docker API的情况下,是牺牲平台的松耦合性和安全性,还是增加平台的复杂性,是一个比较难抉择的事情。也许可以通过namespace虚拟集群可以相对简单的解决这个问题,但这些应用和Kubernetes紧耦合,在不同平台之间可能就不容易迁移,这是我们测试机器学习平台很看重的一点——平台的可移植性。

(一) 弹性伸缩

容器最重要的特性就是弹性。失去了弹性也就失去了灵魂,我们平台初始设计支持部署后的自动或手动的弹性伸缩策略,但未考虑通过容器拉起别的容器或扩展别的容器的问题。容器的弹性伸缩策略可以在界面设置,但却没法配置自动按需启停扩展容器。这的确是需要开放Kubernetes API。或许可以在平台层通过租户等相应的机制来实现资源隔离和安全调度,但应用在平台间迁移时可能需要做些调整。

(二) 资源扩展

容器或Pod根据需要的资源由Kubernetes调度其到相应的节点上。资源不足时,容器可能需要迁移到别的节点。如果整个namespace资源不足,可能需要扩展资源以保证业务服务的正常运行。比如为namespace增加节点,或者为节点增加资源。
从平台设计来说,建议分为两个层面,租户资源扩展和平台资源扩展,这也是我们平台设计的两个视角。租户资源不足时,从平台备用资源中选择,通过标签标识加入该租户成为其资源。可实现手动或自动扩展。平台资源不足时,或设定可用资源低于某个百分点或若干个节点时,通过云管平台调度节点加入容器平台,作为备用扩展资源。大量资源闲置时,可以自动移出,以实现资源的充分利用。

三、 应用部署调度扩展需求

同时我们面临着应用的多集群、甚至多数据中心和多云环境的部署需求。容器调度可能不只是限于一个特定集群中,从高可用、安全、容错等方面考虑也可能需要在多个集群中调度,或者集群位于不同的数据中心以实现备份容错等能力,甚至是不同的云平台之间实现调度。

(一) 多集群调度

多集群指的是Kubernetes物理集群,通过API网关实现服务的总控,服务实例可以调度到不同的集群上,以实现服务的负载均衡、容错、安全备份等能力。

(二) 多数据中心调度

Kubernetes集群可能位于不同的数据中心,以防止某物理地点的异常,比如断电、不可抗力影响等。

(三) 多云调度

混合云可能是一个趋势,某些业务应用可能会分别运行于不同的云平台,或者为了IaaS、PaaS、私有云、公有云、专有云资源的整合,应用服务或容器可以根据需要调度到不同的云平台上。


作者:汪照辉 王作敬 中国银河证券股份有限公司 信息技术部IT研发中心

原题:容器云之容器调度管理


 相关阅读:

金融行业建设容器云平台 8 个难点问题解析

证券行业容器云落地实践分享

银行容器云平台建设的需求分析与关键设计 | 实践经验总结


点击阅读原文关注社区 容器技术主题 ,将会不断更新优质资料、文章,您也可以前往提出疑难问题,与同行切磋交流:


下载 twt 社区客户端 APP

与更多同行在一起

高手随时解答你的疑难问题

轻松订阅各领域技术主题

浏览下载最新文章资料


长按识别二维码即可下载

或到应用商店搜索“twt”


长按二维码关注公众号

继续滑动看下一个

容器云实践分享之容器调度管理

汪照辉 王作敬 twt企业IT社区
向上滑动看下一个

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存